package com.omd.client.server;

import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpHeaders.Names.LOCATION;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;

import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

import com.system.auth.AuthUtil;
import com.system.comm.enums.WriteType;
import com.system.comm.utils.FrameJsonUtil;
import com.system.comm.utils.FrameMapUtil;
import com.system.comm.utils.FrameSpringBeanUtil;
import com.system.comm.utils.FrameStringUtil;
import com.system.handler.Dispatcher;
import com.system.handler.model.ResponseCode;
import com.system.handler.model.ResponseFrame;
import com.system.handler.model.ResponseView;

/**
 * 简单的处理http请求
 * @author yuejing
 * @date 2016年1月21日 下午2:15:49
 * @version V1.0.0
 */
public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

	private static final Logger LOGGER = Logger.getLogger(HttpServerHandler.class);
	/*private static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
	private static final String HTTP_DATE_GMT_TIMEZONE = "GMT";*/

	@Override
	public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
		if (!request.getDecoderResult().isSuccess()) {
			sendError(ctx, HttpResponseStatus.BAD_REQUEST);
			return;
		}

		//判断请求
		HttpMethod method = request.getMethod();
		//得到请求路径
		String uri = null;
		String httpBody = null;
		Map<String, String> params = new HashMap<String, String>();
		if(HttpMethod.GET == method) {
			String[] addressArr = request.getUri().split("\\?");
			uri = addressArr[0];
			if(addressArr.length > 1) {
				httpBody = addressArr[1];
			}
		} else if(HttpMethod.POST == method) {
			uri = request.getUri();
			//得到请求主体内容
			httpBody = request.content().toString(Charset.defaultCharset());
		} else {
			sendError(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED);
			return;
		}
		
		if(FrameStringUtil.isEmpty(httpBody)) {
			sendError(ctx, HttpResponseStatus.FORBIDDEN);
			return;
		}
		
		//获取参数
		String[] paramArr = httpBody.split("&");
		if(paramArr != null && paramArr.length > 0) {
			for (String p : paramArr) {
				String[] kv = p.split("=");
				if(kv != null && kv.length == 2) {
					String value = kv[1];
					if(FrameStringUtil.isNotEmpty(value)) {
						value = FrameStringUtil.unescape(value);
					}
					params.put(kv[0], value);
				}
			}
		}

		

		//LOGGER.info("uri: " + uri + "\n httpBody: " + httpBody);

		//TODO 可判断路径是否存在
		/*if() {
			sendError(ctx, HttpResponseStatus.NOT_FOUND);
		}*/

		//可进行权限的验证, 校验客户端提交的client_sercret是否正确
		String clientId = FrameMapUtil.getString(params, "clientId");
		String sign = FrameMapUtil.getString(params, "sign");
		String time = FrameMapUtil.getString(params, "time");

		LOGGER.info("{ clientId:" + clientId + ", time:" + time + ", sign:" + sign + " } 请求地址: " + uri + "\n 请求参数: " + FrameJsonUtil.toString(params));
		
		if(!AuthUtil.authVerify(clientId, time, sign)) {
			LOGGER.error("非法请求(abnormal signature): { clientId:" + clientId + ", time:" + time + ", sign:" + sign + " } 请求地址: " + uri);
			ResponseFrame frame = new ResponseFrame();
			frame.setCode(ResponseCode.ABNORMAL_SIGNATURE.getCode());
			frame.setMessage(ResponseCode.ABNORMAL_SIGNATURE.getMessage());
			sendError(ctx, HttpResponseStatus.FORBIDDEN);
			return;
		}

		//这里处理业务请求
		Dispatcher business = FrameSpringBeanUtil.getBean(Dispatcher.class);
		Object object = business.process(uri, FrameMapUtil.getString(params, "params"));
		if(object instanceof ResponseFrame) {
			writeResponse(ctx, (ResponseFrame) object, WriteType.JSON);
		} else if(object instanceof ResponseView) {
			//处理重定向
			ResponseView view = (ResponseView) object;
			sendRedirect(ctx, view.getView());
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		LOGGER.error("服务异常: " + cause.getMessage(), cause);
		if (ctx.channel().isActive()) {
			sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
		}
	}

	/**
	 * 写入内容到页面
	 * @param ctx
	 * @param content
	 */
	private static void writeResponse(final ChannelHandlerContext ctx, ResponseFrame frame, WriteType writeType) {
		if (ctx.channel().isWritable()) {
			String content = FrameJsonUtil.toString(frame);
			FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(content, CharsetUtil.UTF_8));
			response.headers().set(HttpHeaders.Names.CONTENT_TYPE, writeType.getCode() + "; charset=utf-8");
			/*FullHttpResponse response = null;
			if (frame.getCode().intValue() == ResponseCode.SUCC.getCode()) {
				String content = FrameJsonUtil.toString(frame);
				response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(content, CharsetUtil.UTF_8));
				response.headers().set(HttpHeaders.Names.CONTENT_TYPE, writeType.getCode() + "; charset=utf-8");
			} else {
				response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
			}
			if (response.content() != null) {
				response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes());
			}*/

			ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);

			/*final ChannelFuture f = ctx.writeAndFlush(response);

			f.addListener(new ChannelFutureListener() {
				@Override
				public void operationComplete(ChannelFuture future) {
					assert f == future;
					//请注意,close()方法也可能不会立马关闭，他也会返回一个ChannelFuture。
					ctx.close();
				}
			});*/
		}
	}

	/**
	 * 重定向到新的地址
	 * @param ctx
	 * @param newUri
	 */
	private static void sendRedirect(ChannelHandlerContext ctx, String newUri) {
		FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.FOUND);
		response.headers().set(LOCATION, newUri);

		// Close the connection as soon as the error message is sent.
		ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
	}

	/**
	 * 发送异常信息
	 * @param ctx
	 * @param status
	 */
	private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
		FullHttpResponse response = new DefaultFullHttpResponse(
				HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));
		response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");

		// Close the connection as soon as the error message is sent.
		ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
	}

	/**
	 * When file timestamp is the same as what the browser is sending up, send a "304 Not Modified"
	 *
	 * @param ctx
	 *            Context

	private static void sendNotModified(ChannelHandlerContext ctx) {
		FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_MODIFIED);
		setDateHeader(response);

		// Close the connection as soon as the error message is sent.
		ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
	} */

	/**
	 * Sets the Date header for the HTTP response
	 *
	 * @param response
	 *            HTTP response

	private static void setDateHeader(FullHttpResponse response) {
		SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
		dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));

		Calendar time = new GregorianCalendar();
		response.headers().set(DATE, dateFormatter.format(time.getTime()));
	} */

}